import Util from "../utils/Util";
import LabRegister from "./LabRegister";
export default {
    mixins: [LabRegister],
    inject: {
        findElement: {
            from: 'findElement',
            default: function (){
                return function () {
                    return []
                }
            }
        },
        openWindow: {
            from: 'openWindow',
            default: function (){
                return function () {
                    return false
                }
            }
        },
        closeWindow: {
            from: 'closeWindow',
            default: function (){
                return function () {
                    return false
                }
            }
        },
        /**
         * 应用信息注入
         */
        appInfo: {
            from: 'appInfo',
            default: function () {
                return { appId: '0' }
            }
        },
        queryByModel: {
            from: 'queryByModel',
            default: function (){
                return new Promise(resolve => { resolve({})})
            }
        },
        saveByModel: {
            from: 'saveByModel',
            default: function (){
                return new Promise(resolve => { resolve({})})
            }
        },
        removeByModel: {
            from: 'removeByModel',
            default: function (){
                return new Promise(resolve => { resolve({})})
            }
        },
    },
    computed: {
        api() {
            return process.env.VUE_APP_BASE_API
        },
        userInfo(){
            return this.$store.state.userInfos.userInfo;
        }
    },
    created() {
        this.dispatchEvent('created')
            .then(()=>{})
    },
    methods: {
        /**
         * 组件自身事件触发
         * @param trigger      目标事件
         * @param args         参数
         * @return {Promise<unknown>}
         */
        dispatchEvent(trigger, args) {
            return new Promise(resolve => {
                if (!this.element) {
                    resolve({code: 200})
                    return;
                }
                const { events } = this.element
                if (Util.isEmpty(events) || Util.isEmpty(trigger)){
                    resolve({code: 202, msg: '未匹配到组件事件'})
                } else {
                    const targets = events.filter(item => item.trigger === trigger)
                    if (Util.isEmpty(targets)){
                        resolve({code: 203,msg: '未匹配到组件目标事件'})
                        return
                    }
                    const promises = []
                    targets.forEach(target => {
                        if (target.callMethod) {
                            promises.push(this.remoteExecuteJs(target,args))
                        } else {
                            promises.push(this.executeJs(target.eventScript, args))
                        }
                    })
                    Promise.all(promises)
                        .then((ress) => {
                            for (let i = 0; i < ress.length; i++) {
                                const res = this.adapterRes(ress[i])
                                if (res.code !== 200) {
                                    resolve(res)
                                    return
                                }
                            }
                            resolve(this.adapterRes(ress[0]))
                        })
                }
            })
        },
        /**
         * 获取远程js搅拌并执行
         * @param event 事件定义
         * @param args  参数
         */
        remoteExecuteJs(event, args){
           return new Promise(resolve => {
               this.$get('/method/loadByCallCmd/' + event.callMethod + '?appId=' + this.appInfo.appId)
                   .then(res => {
                       if (res.code === 200) {
                           if (res.data) {
                               resolve(this.executeJs(res.data.methodBody, args))
                           } else if (event.eventScript) {
                               resolve(this.executeJs(event.eventScript, args))
                           } else {
                               resolve({ code: 500, msg: '函数不存在'})
                           }
                       } else {
                           resolve({ code: 500, msg: '函数查询错误'})
                       }
                   })
           })
        },
        /**
         * js 执行
         * @param script        脚本
         * @param args          参数
         * @return {Promise<unknown>}
         */
        executeJs(script, args) {
            return new Promise((resolve) => {
                if (Util.isEmpty(script)) {
                    resolve({ code: 200 })
                } else {
                    const { element, modelData } = this
                    if (Util.isEmpty(args)) {
                        args = { element, modelData, $this: this, parentElement: this.parentElement, parentView: this.parentView }
                    } else {
                        if (!args.element) {
                            args.element = element
                        }
                        if (!args.modelData) {
                            args.modelData = modelData
                        }
                        if (!args.$this) {
                            args.$this = this
                        }
                        if (!args.parentElement) {
                            args.parentElement = this.parentElement
                        }
                        if (!args.parentView) {
                            args.parentView = this.parentView
                        }
                        if (!args.appInfo) {
                            args.appInfo = this.appInfo
                        }
                        if (!args.userInfo) {
                            args.userInfo = this.userInfo
                        }
                    }
                    // 方法回调
                    if (script instanceof Function) {
                        script(args)
                        resolve({ code: 200 })
                        return
                    }
                    // 异步执行
                    const execDefine = ['args']
                    const execArgs = [args]
                    execDefine.push(`return new Promise((resolve) => { \n ${script} \n })`)
                    const exFun = Function.apply(this, execDefine)
                    exFun.apply(this, execArgs)
                        .then(res => {
                            resolve(this.adapterRes(res))
                        })
                        .catch((e) => {
                            console.error(script, e)
                            resolve({ code: 500, msg: `JS脚本执行失败` })
                        })
                }
            })
        },
        /**
         * 触发组件事件
         * @param key           组件mapper
         * @param trigger       目标事件
         * @param matchObj      详细匹配对象
         * @return {Promise<unknown>}
         */
        dispatchElementEvent(key, trigger, matchObj) {
            return new Promise(resolve => {
                if (Util.isEmpty(key) || Util.isEmpty(trigger)){
                    resolve({code: 200})
                } else {
                    const $matchElement= this.findElement(key, matchObj)
                    if (Util.isEmpty($matchElement)){
                        resolve({code: 201, msg: '未发现组件'})
                    } else {
                        $matchElement.dispatchEvent(trigger)
                            .then((res) => {
                                resolve(this.adapterRes(res))
                        })
                    }
                }
            })
        },
        /**
         * 结果适配。确保方法出口都是{ code: xxx, msg: xxx, data: xxx } 结构`
         * @param res
         */
        adapterRes(res) {
            if (this.$Util.isObj(res)) {
                const keys = Object.keys(res)
                if (keys.includes('code') && keys.includes('msg')) {
                    return res
                } else if (keys.includes('msg')) {
                    Object.assign(res, { code: 500 })
                } else if (keys.includes('code')) {
                    if (res.code !== 200) {
                        Object.assign(res, { msg: '操作失败' })
                    } else {
                        return res
                    }
                }
            }
            return { code: 200, data: res }
        },
        /**
         * 后台函数调用
         * @param callCmd       调用指令
         * @param args          参数对象,为空时为当前 modelData
         * @return {Promise<unknown>}
         */
        callMethod(callCmd, args) {
            return new Promise(resolve => {
                this.$post('/method/callMethod/' + callCmd + "?appId=" + this.appInfo.appId, args || this.modelData )
                    .then(res => {
                        resolve(res)
                    })
            })
        }
    }
}
